package com.sensor;

import com.ideal.Interface.DevInterface;
import java.io.IOException;
import java.math.BigInteger;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Broadcast extends Thread implements DevInterface {

    private final int remotePort;
    private DatagramSocket sock;
    private ArrayList<Sensor> mClientList = new ArrayList<Sensor>();

    /**
     *
     * @param b
     */
    public static void printHexString(byte[] b) {
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            System.out.print(hex.toUpperCase());
        }
        System.out.print('\n');
    }

    /**
     *
     * @param _remotePort
     */
    public Broadcast(int _remotePort) {
        remotePort = _remotePort;
        try {
            SocketAddress localAddr = new InetSocketAddress("0.0.0.0", 60012);
            sock = new DatagramSocket(null);
            sock.setBroadcast(true);
            //sock.setReuseAddress(true);
            sock.bind(localAddr);

        } catch (SocketException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     *
     */
    @Override
    public void run() {
        try {
            receive();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @throws IOException
     */
    private void receive() throws IOException {
        byte[] buffer = new byte[65507];
        //@SuppressWarnings("resource")
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
        System.out.print("Start to Rececive!\n");
        while (true) {
            //System.out.print("before recv\n");
            sock.receive(packet);
            //System.out.print("end recv\n");
            String s = new String(packet.getData(), 0, packet.getLength());
            ByteBuffer buf = ByteBuffer.wrap(packet.getData(), 0, packet.getLength());
            RSFFrame a = new RSFFrame();
            a.FromByteStream(buf.array());

            // ����µĶ���, ��Ӷ����ʱ��ȷ��ͨ�����ͣ�
            Sensor new_find = new Sensor(a, 10050);
            Iterator<Sensor> it = mClientList.iterator();
            while (it.hasNext()) {
                Sensor e = it.next();
                if (e.GetIpAddress() == new_find.GetIpAddress()) {
                    it.remove();
                }
            }
            mClientList.add(new_find);
            packet.setLength(buffer.length);
            //printHexString(packet.getData());
        }
    }

    /**
     *
     * @param msg
     * @param port
     * @throws IOException
     */
    public void send(String msg, int port) throws IOException {
        System.out.print("end end message\n");
        DatagramPacket dp = new DatagramPacket(msg.getBytes(), msg.getBytes().length,
                InetAddress.getByName("255.255.255.255"), port);
        sock.send(dp);
    }

    /**
     *
     * @param msg
     * @param port
     * @throws IOException
     */
    public void send(byte[] msg, int port) throws IOException {
        DatagramPacket dp = new DatagramPacket(msg, msg.length,
                InetAddress.getByName("255.255.255.255"), port);
        System.out.print("before send\n");
        this.sock.send(dp);
        System.out.print("end send\n");
    }

    /**
     *
     * @param port
     * @throws IOException
     */
    public void QueryDevices(int port) throws IOException {
        RSFFrame f = new RSFFrame();
        f.SetOpCode(RSFFrame.OpType.QUERY);
        send(f.GetByteStream(), port);
    }

    /**
     *
     * @return
     */
    public ArrayList<Sensor> GetSensors() {
        return mClientList;
    }

    /**
     *
     * @return
     */
    public int GetSensorsCount() {
        return mClientList.size();
    }

    public boolean AddNewSensor(String ip, int port) {
        try {
            Sensor sen = new Sensor(InetAddress.getByName(ip), port);

            Iterator<Sensor> it = mClientList.iterator();
            while (it.hasNext()) {
                Sensor e = it.next();
                if (e.GetIpAddress() == sen.GetIpAddress()) {
                    it.remove();
                }
            }
            sen.SetNetwork(Sensor.NetType.UDP, InetAddress.getByName(ip), port);
            mClientList.add(sen);

        } catch (Exception ex) {
            return false;
        }
        return true;
    }

    public List<Map> getDevInfo() {
        List<Map> list = null;
        try {
            list = new ArrayList<Map>();
            for (Sensor sensor : mClientList) {
                Map<String, Object> map = sensor.getDevInfo();
                if (map != null) {
                    list.add(map);
                }
            }
        } catch (IOException ex) {
            
        }
        return list;
    }

    /**
     *
     * @param index
     * @param ip
     * @param port
     * @throws IOException
     */
    public void SetDeviceIp(int index, InetAddress ip, int port) throws IOException {
        if (index < 0 || index >= mClientList.size()) {
            System.out.print("error index\n");
            return;
        }
        Sensor s = mClientList.get(index);
        RSFFrame f = s.SetIpAddress(ip);
        System.out.print(f);
        send(f.GetByteStream(), port);
    }

    public ArrayList<String> GetSupportDevices() {
        return null;
    }

    private void SearchUDPDevcie(int port) throws IOException {
        RSFFrame f = new RSFFrame();
        f.SetOpCode(RSFFrame.OpType.QUERY);
        send(f.GetByteStream(), port);
    }

    private void SearchSNMPDevice() {
        // Ŀǰͨ���ļ�����
    }

}
